/*
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "ie_exp_EPUB201.h"

#define XHTML_DOCTYPE "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">"

static void
epub201_gsf_output_write(GsfOutput *output, size_t num_bytes, guint8 const *data)
{
  if (!gsf_output_write(output, num_bytes, data)) {
    UT_DEBUGMSG(("DOM: gsf_output_write() failed\n"));
    UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
  }
}

static void
epub201_gsf_output_close(GsfOutput *output)
{
  if (!gsf_output_close(output)) {
    const GError * err = gsf_output_error(output);
    UT_DEBUGMSG(("DOM: gsf_output_close() failed\n"));
    if (err) {
      UT_DEBUGMSG(("DOM: reason: %s\n", err->message));
    }
    UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
  }
  g_object_unref(output);
}

static void
epub201_close_n_tags(GsfXMLOut *xmlOut, int count)
{
	for (int i = 0; i < count; i++)
	{
		gsf_xml_out_end_element(xmlOut);
	}
}


/*****************************************************************************/
/*****************************************************************************/
IE_Exp_EPUB201::IE_Exp_EPUB201(PD_Document * pDocument)
		: IE_Exp(pDocument)
{

}
IE_Exp_EPUB201::~IE_Exp_EPUB201()
{

}

UT_Error IE_Exp_EPUB201::_writeDocument()
{
	IE_Exp_EPUB201_Listener* listener = new IE_Exp_EPUB201_Listener(getDoc());

	EPUB_Shared_Document pDocument = listener->getDocument();

	UT_return_val_if_fail (getFp(), UT_ERROR);
	m_outputFile = GSF_OUTFILE(gsf_outfile_zip_new (getFp(), NULL));

	UT_return_val_if_fail(m_outputFile, UT_ERROR);


	GsfOutput * mimetype = gsf_outfile_new_child (m_outputFile, "mimetype", FALSE);
	if (!mimetype)
	{
		epub201_gsf_output_close(GSF_OUTPUT(m_outputFile));
		return UT_ERROR;
	}

	epub201_gsf_output_write(mimetype, strlen(EPUB_MIMETYPE), (const guint8 *)EPUB_MIMETYPE);
	epub201_gsf_output_close(mimetype);

	// Create container META-INF directory and write container.xml there
	GsfOutput *metainfDir = gsf_outfile_new_child(m_outputFile, "META-INF", TRUE);
	if (!metainfDir)
	{
		epub201_gsf_output_close(GSF_OUTPUT(m_outputFile));
		return UT_ERROR;
	}
	EPUB201_ContainerWriter::WriteMetadata(getDoc(), metainfDir);
	epub201_gsf_output_close(metainfDir);

	// Now it`s time to write publication content itself
	oebpsDir = gsf_outfile_new_child(m_outputFile, "OEBPS", TRUE);
	if (!oebpsDir)
	{
		epub201_gsf_output_close(GSF_OUTPUT(m_outputFile));
		return UT_ERROR;
	}

	m_imagesDir = gsf_outfile_new_child(GSF_OUTFILE(oebpsDir), "images", true);
	if (!m_imagesDir)
	{
		epub201_gsf_output_close(GSF_OUTPUT(m_outputFile));
		return UT_ERROR;
	}

	EPUB201_StructureWriter::WriteStructure(pDocument, oebpsDir);
	EPUB201_StructureWriter::WriteImages(pDocument, m_imagesDir);
	epub201_gsf_output_close(m_imagesDir);
	epub201_gsf_output_close(oebpsDir);


	epub201_gsf_output_close(GSF_OUTPUT(m_outputFile));
	 return UT_OK;
}

/*****************************************************************************/
/*****************************************************************************/
bool EPUB201_ContainerWriter::WriteMetadata(PD_Document *pDocument, GsfOutput *metadataDir)
{
	GsfOutput *containerFile = gsf_outfile_new_child(
			GSF_OUTFILE(metadataDir), "container.xml", FALSE);
	if(!containerFile)
	{
		return false;
	}

	GsfXMLOut * containerXml = gsf_xml_out_new(containerFile);
	UT_String opfPath;
	//UT_String_sprintf(opfPath, "OEBPS/%s.opf", )

	// <container>
	gsf_xml_out_start_element(containerXml, "container");
	gsf_xml_out_add_cstr(containerXml, "version", "1.0");
	gsf_xml_out_add_cstr(containerXml, "xmlns", "urn:oasis:names:tc:opendocument:xmlns:container");
		// <rootfiles>
		gsf_xml_out_start_element(containerXml, "rootfiles");
			// <rootfile>
			gsf_xml_out_start_element(containerXml, "rootfile");
			gsf_xml_out_add_cstr(containerXml, "media-type", "application/oebps-package+xml");
			gsf_xml_out_add_cstr(containerXml, "full-path", opfPath.c_str());
			gsf_xml_out_end_element(containerXml);
			// </rootfile>
		// </rootfiles>
		gsf_xml_out_end_element(containerXml);
	// </container>
	gsf_xml_out_end_element(containerXml);

	epub201_gsf_output_close(containerFile);

	return true;

}


bool EPUB201_ContainerWriter::WriteTOC(PD_Document* pDocument,
		GsfOutput *contentsDir)
{

}

/*****************************************************************************/
/*****************************************************************************/
std::vector<EPUB_Shared_Element	>* EPUB201_StructureWriter::
	_CreateTrace(EPUB_Shared_Document pDocument)
{

	// Resulting elements
	std::vector<EPUB_Shared_Element>* traverse = new
			std::vector<EPUB_Shared_Element>();

	// Elements that are currently processed
	std::vector<EPUB_Shared_Element>* stack = new
			std::vector<EPUB_Shared_Element>();

	EPUB_Shared_Element current;

	stack->push_back(pDocument->getDocumentRoot());
	do
	{
		current = stack->back();
		stack->pop_back();
		traverse->push_back(current);

		for(int i = 0; i < current->getChildren().size(); i++)
		{
			stack->push_back(current->getChildren().at(current->getChildren().size() - 1 - i));
		}

	} while (stack->size() > 0);

	return traverse;
}
bool EPUB201_StructureWriter::WriteStructure(EPUB_Shared_Document pDocument,
		GsfOutput *contentsDir)
{

	// TODO: Add breaking document into chapters
	GsfOutput *contentsFile = gsf_outfile_new_child(
			GSF_OUTFILE(contentsDir), "book.html", FALSE);
	if(!contentsFile)
	{
		return false;
	}

	GsfXMLOut * contentsXml = gsf_xml_out_new(contentsFile);

	gsf_xml_out_set_doc_type(contentsXml, XHTML_DOCTYPE);

	std::vector	<EPUB_Shared_Element>* trace =
			_CreateTrace(pDocument);


	int lastLevel = 0;

	for(int i = 0; i < trace->size(); i++)
	{
		EPUB_Shared_Element element = trace->at(i);



		if ((lastLevel >= element->getLevel()) && (element->getLevel() != 0))
		{
			epub201_close_n_tags(contentsXml, lastLevel - element->getLevel() + 1);
		}

		lastLevel = element->getLevel();

		// Open current element`s tag
		gsf_xml_out_start_element(contentsXml,
				element->getName().utf8_str());

		UT_DEBUGMSG(("Started tag: %s Level: %d", element->getName().utf8_str(), lastLevel));


		// Write attributes assigned to element
		for(int currentAttribute = 0;
				currentAttribute < element->getAttributes().size();
				currentAttribute++)
		{
			gsf_xml_out_add_cstr(contentsXml,
					element->getAttributes().keys(true)->getNthItem(currentAttribute)->c_str(),
					element->getAttributes().pick(*element->getAttributes().
							keys(true)->getNthItem(currentAttribute))->utf8_str());
		}

		if ((element->getValue() != NULL) && (element->getValue() != UT_UTF8String()))
		{
			gsf_xml_out_add_cstr(contentsXml,
					NULL,
					(element->getValue().utf8_str()));
		}



	}

	epub201_close_n_tags(contentsXml,lastLevel + 1);
	epub201_gsf_output_close(contentsFile);
	return true;
}

bool EPUB201_StructureWriter::WriteStyles(PD_Document* pDocument,
		GsfOutput *cssDir)
{
	return true;
}

bool EPUB201_StructureWriter::WriteImages(EPUB_Shared_Document pDocument, GsfOutput *imagesDir)
{

	for (std::list<EPUB_Shared_EmbeddedFile>::iterator i = pDocument->getFiles().begin();
			i != pDocument->getFiles().end(); i++)
	{
		EPUB_Shared_EmbeddedFile file = *i;

		if (file->getFileType() == EFT_Image)
		{
			GsfOutput * imgFile =
					gsf_outfile_new_child (GSF_OUTFILE(imagesDir),
							file->getName().utf8_str(), FALSE);
			epub201_gsf_output_write(imgFile,
					file->getData()->getLength(),
					file->getData()->getPointer(0));
			epub201_gsf_output_close(imgFile);

		}
	}
	return true;
}
